/**
 * @method Method 常用开发解决方案
 * @author Lkx
 * @for Kxui
 *
 * @method urlData 获取浏览器地址参数
 * @method repStr 替换指定字符(通过已知字符查找)
 * @method chaStr 替换指定字符(通过下标查找)
 * @method insStr 插入指定字符
 * @method queStr 获取指定字符前/后的所有字符
 * @method midStr 获取指定字符中间的字符
 * @method substrByByte 文本多行省略(字节判断)
 * @method sortArr 数组排序(冒泡排序)
 * @method delRepArr 数组去重
 * @method countArr 元素在数组中出现的次数
 * @method delEle 删除数组中某个元素(通过已知元素查找)
 * @method remEle 删除数组中某个元素(通过下标查找)
 * @method intersect 对比数组取出交集
 * @method formTest 表单验证
 * @method hasClass 查询是否存在class值
 * @method addClass 增加class值
 * @method delClass 移除class值
 * @method setCache 设置本地缓存
 * @method getCache 获取本地缓存
 * @method delCache 删除本地缓存
 * @method setCookie 设置cookie
 * @method getCookie 获取cookie
 * @method delCookie 删除cookie
 * @method compare 数据对比(内容与数据类型)
 * @method setHis 记录历史搜索信息
 * @method getHis 获取历史搜索信息
 * @method delHis 删除历史搜索信息
 * @method dateGet 获取当前时间戳
 * @method dateAppoint 获取指定时间戳
 * @method dateDiff 获取两个时间的时间差(返回天数)
 * @method dateTurn 时间戳转换日期
 * @method getDom 获取节点(转为原生dom节点)
 * @method addDom 增加节点
 * @method atrDom 替换或创建自定义属性
 * @method delAtrDom 删除自定义属性
 * @method sonDom 获取所有子节点(一层)
 * @method sonQueDom 获取指定子节点
 * @method random 生成指定长度的随机字符串
 * @method randomNum 生成随机数字
 * @method randomColor 生成随机颜色
 * @method mouse 获取鼠标/手势位置
 * @method gesture 获取鼠标/手势方向
 * @method accAdd 防误差加法运算
 * @method accSub 防误差减法运算
 * @method accMul 防误差乘法运算
 * @method accDiv 防误差除法运算
 * @method decimal 保留任意位小数
 * @method decimalPlaces 获取小数点位数
 * @method money 金钱显示格式(每隔三位数字添加一个逗号)
 * @method moneyToChinese 数字金额大写转换
 * @method bankCard 银行卡号(每隔四个数字添加一个空格)
 * @method aniScroll 滚动条滚动动画
 * @method stopProp 阻止事件冒泡
 * @method deepCopy 对象深拷贝
 * @method copyText 复制文本到剪贴板
 * @method setStyle 设置元素样式(行内样式)
 * @method getStyle 获取元素样式
 * @method delSpace 字符串/对象去空格
 * @method repHtmlTag 替换所有HTML标签
 * @method delHtmlTag 去掉所有HTML标签
 * @method enter 键盘回车事件
 * @method fontAdapt 移动端尺寸自适应
 * @method percent 获取百分比
 * @method monitor 监听输入框事件(处理中文输入问题)
 * @method getIn 主动防御
 * @method timeTaken 测试函数所花费的时间
 * @method drag 元素拖拽
 */

(function (factory) {

  if ((typeof exports === 'object') && (typeof module !== 'undefined')) {
    module.exports = factory();
  } else {
    window.Kxui.method = factory();
  }

}(function () {

  'use strict';

  let Kxui = window.Kxui;

  /**
   * 常用开发解决方案
   * @method Method
   */
  let Method = function () {
    this.name = 'Method';
    this.info = 'Common Development Solutions';
  };

  Method.fn = Method.prototype;

  /**
   * 获取浏览器地址参数
   * @method urlData
   * @for Method
   * @param {string} data 需要拿取的参数名
   * @return {string} 返回参数值或空
   */
  Method.fn.urlData = function (data) {
    if (presence(data, 'string')) {
      let result = window.location.search.match(new RegExp('[\\?\\&]' + data + '=([^\\&]+)', 'i'));
      return ((!result || result.length < 1) ? '' : decodeURI(result[1]));
    }
    throws(0, 'urlData', 'data');
  };

  /**
   * 替换指定字符(通过已知字符查找)
   * @method repStr
   * @for Method
   * @param {string} str 需要操作的字符串
   * @param {string} app 需要替換的字符
   * @param {string} rep 替换之后的字符(不填将默认为空)
   * @return {string} 返回替换后的字符串
   */
  Method.fn.repStr = function (str, app, rep) {
    if (presence(str, 'string') && presence(app, 'string')) {
      if (rep && !presence(rep, 'string') && !presence(rep, 'number')) {
        throws(0, 'repStr', 'rep');
        return str;
      } else {
        rep = rep || '';
        return str.replace(new RegExp(app, 'g'), rep);
      }
    }
    throws(0, 'repStr', (presence(str, 'string') ? 'app' : 'str'));
  };

  /**
   * 替换指定字符(通过下标查找)
   * @method chaStr
   * @for Method
   * @param {string} str 需要操作的字符串
   * @param {number} ind 需要替換的下标
   * @param {string} rep 替换之后的字符(不填将默认为空)
   * @return {string} 返回替换后的字符串
   */
  Method.fn.chaStr = function (str, ind, rep) {
    if (presence(str, 'string') && presence(ind, 'number')) {
      if (rep && !presence(rep, 'string') && !presence(rep, 'number')) {
        throws(0, 'chaStr', 'rep');
        return str;
      } else {
        ind = +ind;
        rep = rep || '';
        let sFrontPart = str.substr(0, ind);
        let sTailPart = str.substr(ind + 1, str.length);
        let sRet = sFrontPart + rep + sTailPart;
        return sRet;
      }
    }
    throws(0, 'chaStr', (presence(str, 'string') ? 'ind' : 'str'));
  };

  /**
   * 插入指定字符
   * @method insStr
   * @for Method
   * @param {string} str 需要操作的字符串
   * @param {string/number} after 在某字符之后或某个下标之后增加
   * @param {string} app 需要插入的字符
   * @return {string} 返回插入后的字符串
   */
  Method.fn.insStr = function (str, after, app) {
    if (presence(str, 'string') && (presence(after, 'string') || presence(after, 'number')) && (presence(app, 'string') || presence(app, 'number'))) {
      let S = str.split(after);
      if (presence(after, 'number')) {
        return (str.slice(0, after) + app + str.slice(after));
      } else if (presence(after, 'string') && S.length > 1) {
        S[1] = app + S[1];
        str = S.join(after);
      }
      return str;
    }
    throws(0, 'insStr', (presence(str, 'string') ? ((presence(after, 'string') || presence(after, 'number')) ? 'app' : 'after') : 'str'));
  };

  /**
   * 获取指定字符前/后的所有字符
   * @method queStr
   * @for Method/getStyle
   * @param {string} str 需要操作的字符串
   * @param {string} app 需要指定的字符
   * @param {boolean} pos 前/后 默认(true)后
   * @return {string} 返回前后字符串或空
   */
  Method.fn.queStr = function (str, app, pos) {
    if (presence(str, 'string') && presence(app, 'string')) {
      str = String(str);
      let position = (presence(pos, 'boolean') ? pos : true);
      let result = (str.match(new RegExp(position ? app + '(\\S*)' : '(\\S*)' + app)));
      return ((!result || result.length < 1) ? '' : result[1]);
    }
    throws(0, 'queStr', (presence(str, 'string') ? 'app' : 'str'));
  };

  /**
   * 获取指定字符中间的字符
   * @method midStr
   * @for Method
   * @param {string} str 需要操作的字符串
   * @param {string} fro 前字符
   * @param {string} aft 后字符
   * @return {string} 返回中间的字符串或空
   */
  Method.fn.midStr = function (str, fro, aft) {
    if (presence(str, 'string') && (presence(fro, 'string') || presence(fro, 'number')) && (presence(aft, 'string') || presence(aft, 'number'))) {
      let result = str.match(new RegExp(fro + '(\\S*)' + aft));
      return ((!result || result.length < 1) ? '' : result[1]);
    }
    throws(0, 'midStr', (presence(str, 'string') ? (presence(fro, 'string') ? 'aft' : 'fro') : 'str'));
  };

  /**
   * 文本多行省略(字节判断)
   * @method substrByByte
   * @for Method
   * @param {string} str 字符串
   * @param {number} num 需要保留的字符
   * @return {string} 返回后的新字符
   */
  Method.fn.substrByByte = function (str, num) {
    if (presence(str, 'string') && presence(num, 'number')) {
      let bytesCount = 0;
      for (let i = 0; i < str.length; i++) {
        let c = str.charAt(i);
        if (/^[\u0000-\u00ff]$/.test(c)) {
          bytesCount += 1;
        } else {
          bytesCount += 2;
        }
        if (bytesCount > num) {
          return str.substr(0, i) + '...';
        } else if (bytesCount === num) {
          return str.substr(0, i + 1) + '...';
        }
      }
      return str;
    }
    throws(0, 'substrByByte', (presence(str, 'string') ? 'num' : 'str'));
  };

  /**
   * 数组排序(冒泡排序)
   * @method sortArr
   * @for Method
   * @param {Array} arr 需要操作的数组
   * @param {boolean} dir true:正序/false:倒序
   * @return {Array} 返回排序后数组
   */
  Method.fn.sortArr = function (arr, dir) {
    if (presence(arr, 'object')) {
      let temp = [];
      dir = (presence(dir, 'boolean') ? dir : true);
      for (let i = 0; i < arr.length - 1; i++) {
        let bool = true;
        for (let j = 0; j < arr.length - 1 - i; j++) {
          let condition = (dir ? arr[j] > arr[j + 1] : arr[j] < arr[j + 1]);
          if (condition) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
            bool = false;
          }
        }
        if (bool) {
          break;
        }
      }
      return arr;
    }
    throws(0, 'sortArr', 'arr');
  };

  /**
   * 数组去重
   * @method delRepArr
   * @for Method
   * @param {Array} arr 需要操作的数组
   * @return {Array} 返回去重后的数组
   */
  Method.fn.delRepArr = function (arr) {
    if (presence(arr, 'object')) {
      return Array.from(new Set(arr));
    }
    throws(0, 'delRepStr', 'arr');
  };

  /**
   * 元素在数组中出现的次数
   * @method countArr
   * @for Method/delEle
   * @param {Array} arr 需要操作的数组
   * @param {string} ele 要查找的元素
   * @return {number} 元素出现的次数
   */
  Method.fn.countArr = function (arr, ele) {
    if (presence(arr, 'object') && (presence(ele, 'string') || presence(ele, 'number'))) {
      let num = 0;
      for (let i = 0; i < arr.length; i++) {
        if (ele === arr[i]) {
          num++;
        }
      }
      return num;
    }
    throws(0, 'countArr', (presence(arr, 'object') ? 'ele' : 'arr'));
  };

  /**
   * 删除数组中某个元素(通过已知元素查找)
   * @method delEle
   * @for Method
   * @param {Array} arr 需要操作的数组
   * @param {string/number} app 需要删除的字符
   * @return {Array} 返回新数组
   */
  Method.fn.delEle = function (arr, app) {
    if (presence(arr, 'object') && (presence(app, 'string') || presence(app, 'number'))) {
      for (let i = 0; i < arr.length; i++) {
        let I = arr.indexOf(app);
        if (I >= 0) {
          if (i === I) {
            arr.splice(I, 1);
          }
        } else {
          break;
        }
      }
      return arr;
    }
    throws(0, 'delEle', presence(arr, 'object') ? 'app' : 'arr');
  };

  /**
   * 删除数组中某个元素(通过下标查找)
   * @method remEle
   * @for Method/setHis
   * @param {Array} arr 需要操作的数组
   * @param {number} ind 需要删除的下标
   * @return {Array} 返回新数组
   */
  Method.fn.remEle = function (arr, ind) {
    if (presence(arr, 'object') && presence(ind, 'number')) {
      ind = +ind;
      for (let i = 0; i < arr.length; i++) {
        let I = arr.indexOf(arr[i]);
        if (ind === I) {
          arr.splice(I, 1);
          break;
        }
      }
      return arr;
    }
    throws(0, 'remEle', presence(arr, 'object') ? 'ind' : 'arr');
  };

  /**
   * 对比数组取出交集
   * @method intersect
   * @for Method
   * @param {Array} 对比数组，理论上可以无限多个
   * @return {Array} 交集数组
   */
  Method.fn.intersect = function () {
    let obj = {};
    let result = [];
    for (let i = 0; i < arguments.length; i++) {
      for (let j = 0; j < arguments[i].length; j++) {
        let str = arguments[i][j];
        if (!obj[str]) {
          obj[str] = 1;
        } else {
          obj[str]++;
          if (obj[str] === arguments.length) {
            result.push(str);
          }
        }
      }
    }
    return result;
  };

  /**
   * 表单验证
   * @method formTest
   * @for Method
   * @param {string} data 需要验证的数据
   * @param {string} reg
   *
   * empty:不能为空
   * num:不允许存在小数的数字
   * letter:字母
   * decimal:允许存在小数的数字
   * phone:手机号
   * chinese:中文
   * color:十六进制颜色
   * id:身份证
   * passport:护照(包含香港、澳门)
   * url:链接地址
   * md5:有效的md5格式(32位)
   * email:邮箱
   * IPv4:IPv4地址
   * IPv4:IPv6地址
   *
   * @return {boolean} 根据验证情况进行返回布尔值
   */
  Method.fn.formTest = function (data, reg) {
    if ((presence(data, 'string') || presence(data, 'number')) && presence(reg, 'string')) {
      let regs = {};
      regs.empty = /\S/;
      regs.num = /^\d+$/;
      regs.letter = /^[a-zA-Z]+$/;
      regs.decimal = /^\d+(\.\d+)?$/;
      regs.phone = /^1[3456789]\d{9}$/;
      regs.chinese = /^[\u4e00-\u9fa5]+$/;
      regs.color = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
      regs.id = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i;
      regs.passport = /(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/;
      regs.url = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/;
      regs.md5 = /^[a-f0-9]{32}$/;
      regs.email = /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
      regs.IPv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
      regs.IPv6 = /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i;
      return (!!((regs[reg] && regs[reg].test(data))));
    }
    throws(0, 'formTest', presence(data, 'string') ? 'reg' : 'data');
  };

  /**
   * 查询是否存在class值
   * @method hasClass
   * @for Method/addClass/delClass
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} cls 需要查询的class名称
   * @return {boolean} 根据查询返回布尔值
   */
  Method.fn.hasClass = function (dom, cls) {
    if (presence(dom) && presence(cls, 'string')) {
      dom = this.getDom(dom);
      if (cls.replace(/\s/g, '').length === 0) {
        return false;
      }
      return new RegExp(' ' + cls + ' ').test(' ' + dom.className + ' ');
    }
    throws(0, 'hasClass', presence(dom) ? 'cls' : 'dom');
  };

  /**
   * 增加class值
   * @method addClass
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} cls 需要增加的class名称
   * @return {boolean} 根据成功与否返回布尔值
   */
  Method.fn.addClass = function (dom, cls) {
    if (presence(dom) && presence(cls, 'string')) {
      dom = this.getDom(dom);
      if (!this.hasClass(dom, cls)) {
        dom.className = ((dom.className === '') ? cls : (dom.className + ' ' + cls));
        return true;
      }
      return false;
    }
    throws(0, 'addClass', presence(dom) ? 'cls' : 'dom');
  };

  /**
   * 移除class值
   * @method delClass
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} cls 需要移除的class名称
   * @return {boolean} 根据成功与否返回布尔值
   */
  Method.fn.delClass = function (dom, cls) {
    if (presence(dom) && presence(cls, 'string')) {
      dom = this.getDom(dom);
      if (this.hasClass(dom, cls)) {
        let newClass = (' ' + dom.className.replace(/[\t\r\n]/g, '') + ' ');
        while (newClass.indexOf(' ' + cls + ' ') >= 0) {
          newClass = newClass.replace(' ' + cls + ' ', ' ');
        }
        dom.className = newClass.replace(/^\s+|\s+$/g, '');
        return true;
      }
      return false;
    }
    throws(0, 'delClass', presence(dom) ? 'cls' : 'dom');
  };

  /**
   * 设置本地缓存
   * @method setCache
   * @for Method/setHis
   * @param {string} key 设置缓存名称
   * @param {all} val 设置缓存内容
   * @param {number} tim 设置缓存有效时间，单位 1000/1s
   * @return {boolean} 返回设置动作布尔值
   */
  Method.fn.setCache = function (key, val, tim) {
    if (presence(key, 'string') && presence(val) && !presence(val, 'function')) {
      val = (presence(val, 'object') ? JSON.stringify(val) : val);
      localStorage.setItem(key, val);
      let seconds = +tim;
      if (seconds > 0) {
        let timestamp = (this.dateGet() + seconds);
        localStorage.setItem(key + ' (method.time)', timestamp);
      }
      return true;
    }
    throws(0, 'setCache', presence(key, 'string') ? 'val' : 'key');
  };

  /**
   * 获取本地缓存
   * @method getCache
   * @for Method/setHis/getHis
   * @param {string} key 读取缓存名称
   * @return {string/boolean} 返回获取值或布尔值
   */
  Method.fn.getCache = function (key) {
    if (presence(key, 'string')) {
      let val = '';
      let timestamp = parseInt(localStorage.getItem(key + ' (method.time)'));
      try {
        val = JSON.parse(localStorage.getItem(key));
      } catch (e) {
        val = localStorage.getItem(key);
      }
      if (timestamp && (timestamp < this.dateGet())) {
        this.delCache(key);
        return false;
      }
      return val;
    }
    throws(0, 'getCache', 'key');
  };

  /**
   * 删除本地缓存
   * @method delCache
   * @for Method/getCache/delHis
   * @param {string} key 删除缓存名称
   * @return {boolean} 返回删除动作布尔值
   */
  Method.fn.delCache = function (key) {
    if (presence(key, 'string')) {
      localStorage.removeItem(key);
      localStorage.removeItem(key + ' (method.time)');
      return true;
    }
    throws(0, 'delCache', 'key');
  };

  /**
   * 设置cookie
   * @method setCookie
   * @for Method
   * @param {string} key 设置cookie名称
   * @param {all} val 设置cookie内容
   * @param {number} tim 设置cookie有效时间，单位 1/1天
   * @return {boolean} 返回设置动作布尔值
   */
  Method.fn.setCookie = function (key, val, tim) {
    if (presence(key, 'string') && presence(val) && !presence(val, 'function')) {
      val = (presence(val, 'object') ? JSON.stringify(val) : val);
      let oDate = new Date();
      let seconds = +tim;
      oDate.setDate(oDate.getDate() + seconds);
      document.cookie = key + '=' + val + ';expires=' + oDate;
      return true;
    }
    throws(0, 'setCookie', presence(key, 'string') ? 'val' : 'key');
  };

  /**
   * 获取cookie
   * @method getCookie
   * @for Method
   * @param {string} key 读取cookie名称
   * @return {string/boolean} 返回获取值或布尔值
   */
  Method.fn.getCookie = function (key) {
    if (presence(key, 'string')) {
      let arr = document.cookie.split('; ');
      for (let i = 0; i < arr.length; i++) {
        let arr2 = arr[i].split('=');
        if (arr2[0] === key) {
          return JSON.parse(arr2[1]);
        }
      }
      return false;
    }
    throws(0, 'getCookie', 'key');
  };

  /**
   * 删除cookie
   * @method delCookie
   * @for Method
   * @param {string} key 删除cookie名称
   * @return {boolean} 返回删除动作布尔值
   */
  Method.fn.delCookie = function (key) {
    if (presence(key, 'string')) {
      this.setCookie(key, 1, -1);
      return true;
    }
    throws(0, 'delCookie', 'key');
  };

  /**
   * 数据对比(内容与数据类型)
   * @method compare
   * @for Method/setHis
   * @param {all} dataOne 需要对比的数据一
   * @param {all} dataTwo 需要对比的数据二
   * @return {boolean} 返回数据是否相等的布尔值
   */
  Method.fn.compare = function (dataOne, dataTwo) {
    if (presence(dataOne) && presence(dataTwo)) {
      let props1 = Object.getOwnPropertyNames(dataOne);
      let props2 = Object.getOwnPropertyNames(dataTwo);
      if (props1.length !== props2.length) {
        return false;
      }

      for (let i = 0; i < props1.length; i++) {
        let propName = props1[i];
        if (dataOne[propName] !== dataTwo[propName]) {
          return false;
        }
      }

      if (presence(dataOne, 'number') && presence(dataTwo, 'number')) {
        if (dataOne !== dataTwo) {
          return false;
        }
      }
      return true;
    }
    throws(0, 'compare', presence(dataOne) ? 'dataTwo' : 'dataOne');
  };

  /**
   * 记录历史搜索信息
   * @method setHis
   * @for Method
   * @param {all} data 需要储存的历史记录
   * @param {string/number} num 需要记录历史缓存的数量
   * @return {object} 返回数组对象
   */
  Method.fn.setHis = function (data, num) {
    if (presence(data)) {
      let bars = +num || 6;
      let history = this.getCache('(method.history)') || [];
      let difference = this.accSub(history.length, bars);
      if (history && history.length > 0) {
        let L = history.length;
        for (let i = 0; i < L; i++) {
          if (this.compare(history[i], data)) {
            history = this.remEle(history, i);
            history.unshift(data);
            break;
          } else {
            if (i === (L - 1)) {
              if (i >= (bars - 1)) {
                history = this.remEle(history, i);
              }
              history.unshift(data);
            }
          }
        }
      } else {
        history[0] = data;
      }

      if (difference !== 0) {
        for (let d = 0; d < difference; d++) {
          history = this.remEle(history, history.length - 1);
        }
      }

      this.setCache('(method.history)', history);
      return history;
    }
    throws(0, 'setHis', 'data');
  };

  /**
   * 获取历史搜索信息
   * @method getHis
   * @for Method
   * @return {boolean} 返回获取动作布尔值
   */
  Method.fn.getHis = function () {
    let history = this.getCache('(method.history)');
    return (history ? history : false);
  };

  /**
   * 删除历史搜索信息
   * @method delHis
   * @for Method
   * @return {boolean} 返回获取动作布尔值
   */
  Method.fn.delHis = function () {
    return this.delCache('(method.history)');
  };

  /**
   * 获取当前时间戳
   * @method dateGet
   * @for Method/setCache/getCache
   * @param {boolean} digit 时间戳长度，默认13位(true)，可返回10位及13位时间戳
   * @return {number} 当前时间戳
   */
  Method.fn.dateGet = function (digit) {
    digit = (presence(digit, 'boolean') ? digit : true);
    let time = new Date().getTime();
    let result = (digit ? time : Number(time.toString().substr(0, 10)));
    return result;
  };

  /**
   * 获取指定时间戳
   * @method dateAppoint
   * @for Method
   * @param {string} time 指定日期，格式例：xxxx-xx-xx xx:xx:xx
   * @return {number} 指定时间戳
   */
  Method.fn.dateAppoint = function (time) {
    if (presence(time, 'string')) {
      return (new Date(time)).getTime() / 1000;
    }
    throws(0, 'dateAppoint', 'time');
  };

  /**
   * 获取两个时间的时间差(返回天数)
   * @method dateDiff
   * @for Method
   * @param {number} start 开始时间戳
   * @param {number} end 结束时间戳
   * @return {number} 相差天数
   */
  Method.fn.dateDiff = function (start, end) {
    if (presence(start, 'number') && presence(end, 'number')) {
      start = Number(start);
      end = Number(end);
      return Math.abs(end - start) / (24 * 1000 * 3600);
    }
    throws(0, 'dateDiff', (presence(start, 'number') ? 'end' : 'start'));
  };

  /**
   * 时间戳转换日期
   * @method dateTurn
   * @for Method
   * @param {number} tamp 需要转换的时间戳
   * @param {string} diy 日期分割符号
   * @param {boolean} hour 是否显示时/分/秒
   * @return {string} 返回转换后的日期
   */
  Method.fn.dateTurn = function (tamp, diy, hour) {
    if (presence(tamp, 'number')) {
      let date = new Date((tamp.toString().length === 13) ? tamp : (tamp * 1000));
      let dateDiv = (presence(diy, 'string') ? diy : '-');
      let isHour = (presence(hour, 'boolean') ? hour : true);
      let Y = date.getFullYear();
      let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1);
      let D = (date.getDate().toString().length === 1 ? '0' + date.getDate() : date.getDate());
      let h = (date.getHours().toString().length === 1 ? '0' + date.getHours() : date.getHours());
      let m = (date.getMinutes().toString().length === 1 ? '0' + date.getMinutes() : date.getMinutes());
      let s = (date.getSeconds().toString().length === 1 ? '0' + date.getSeconds() : date.getSeconds());
      return Y + dateDiv + M + dateDiv + D + (isHour ? (' ' + h + ':' + m + ':' + s) : '');
    }
    throws(0, 'dateTurn', 'tamp');
  };

  /**
   * 获取节点(转为原生dom节点)
   * @method getDom
   * @for Method/hasClass/addClass/delClass/atrDom/delAtrDom/sonDom/gesture/copyText/enter/monitor/drag
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {boolean} top 是否获取最顶层节点(默认为false，查看IFrame当前层)
   * @return {object} 节点对象
   */
  Method.fn.getDom = function (dom, top) {
    let Dom = dom;
    let Top = (presence(top, 'boolean') ? top : false);
    let extract = function () {
      if (presence(Dom, 'object')) {
        return Dom;
      } else if (presence(Dom, 'string')) {
        dom = (Top ? window.top.document.querySelectorAll(Dom) : document.querySelectorAll(Dom));
        if (dom.length > 1) {
          return dom;
        } else if (dom.length === 1) {
          return dom[0];
        } else {
          return false;
        }
      }
    };

    if (presence(dom, 'string') || presence(dom, 'object')) {
      try {
        if (dom instanceof jQuery) {
          return dom[0];
        }
        return extract();
      } catch (e) {
        return extract();
      }
    }
    throws(0, 'getDom', 'dom');
  };

  /**
   * 增加节点
   * @method addDom
   * @for Method
   * @param {string} str 字符串节点
   * @return {object} 节点对象
   */
  Method.fn.addDom = function (str) {
    if (presence(str, 'string')) {
      let dom = document.createElement('div');
      dom.innerHTML = str;
      return dom.childNodes[0];
    }
    throws(0, 'addDom', 'str');
  };

  /**
   * 创建或替换自定义属性
   * @method atrDom
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} key 自定义属性键
   * @param {all} val 自定义属性值
   * @return {boolean} 返回创建或查询对象结果
   */
  Method.fn.atrDom = function (dom, key, val) {
    if (presence(dom) && presence(key, 'string')) {
      let D = this.getDom(dom);
      if (!D) {
        throws(1, 'atrDom', dom);
      } else if (presence(val, 'function')) {
        throws(0, 'atrDom', 'val');
      } else if (presence(val)) {
        D.setAttribute(key, val);
        return true;
      } else {
        return D.getAttribute(key);
      }
      return false;
    }
    throws(0, 'atrDom', (presence(dom) ? 'key' : 'dom'));
  };

  /**
   * 删除自定义属性
   * @method delAtrDom
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} key 自定义属性键
   * @return {boolean} 返回操作结果
   */
  Method.fn.delAtrDom = function (dom, key) {
    if (presence(dom) && presence(key, 'string')) {
      let D = this.getDom(dom);
      if (!D) {
        throws(1, 'delAtrDom', dom);
      } else {
        try {
          D.removeAttribute(key);
          return true;
        } catch (e) {
          return false;
        }
      }
    }
    throws(0, 'delAtrDom', (presence(dom) ? 'key' : 'dom'));
  };

  /**
   * 获取所有子节点(一层)
   * @method sonDom
   * @for Method/sonQueDom
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @return {object} 子节点对象
   */
  Method.fn.sonDom = function (dom) {
    if (presence(dom)) {
      dom = this.getDom(dom);
      let child = dom.childNodes;
      if (child) {
        let postChild = [];
        for (let i = 0; i < child.length; i++) {
          if (!(child[i].nodeType === 3 && child[i].nodeName === '#text' && !/\S/.test(child[i].nodeValue))) {
            postChild.push(child[i]);
          }
        }
        return postChild;
      } else {
        return false;
      }
    }
    throws(0, 'sonDom', 'dom');
  };

  /**
   * 获取指定子节点
   * @method sonQueDom
   * @for Method
   * @param {string/object} father 父节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} dom 子节点名称/class值/id值
   * @return {object} 子节点对象
   */
  Method.fn.sonQueDom = function (father, dom) {
    let that = this;
    let result = [];
    if (presence(father) && presence(dom, 'string')) {
      findRecursion(that.sonDom(father));
      return result;
    }

    function findRecursion(fathers) {
      for (let i = 0; i < fathers.length; i++) {
        if ('#' + fathers[i].id === dom || '.' + fathers[i].className === dom || fathers[i].tagName === dom.toUpperCase()) {
          result.push(fathers[i]);
          if (that.sonDom(fathers[i]).length > 0) {
            findRecursion(that.sonDom(fathers[i]));
          }
        } else if (that.sonDom(fathers[i]).length > 0) {
          findRecursion(that.sonDom(fathers[i]));
        }
      }
    }
    throws(0, 'sonQueDom', (presence(father) ? 'dom' : 'father'));
  };

  /**
   * 生成指定长度的随机字符串
   * @method random
   * @for Method
   * @param {number} len 随机字符串长度(默认8位)
   * @return {string} 返回随机结果
   */
  Method.fn.random = function (len) {
    len = +len || 8;
    let str = '';
    for (str = ''; str.length < len; str += Math.random().toString(36).substr(2));
    return str.substr(0, len);
  };

  /**
   * 生成随机数字
   * @method randomNum
   * @for Method/randomColor
   * @param {string/number} minNum 生成的随机数的最小值(默认0)
   * @param {string/number} maxNum 生成的随机数的最大值(默认255)
   * @param {string/number} decimalNum 如果生成的是带有小数的随机数，则指定随机数的小数点后的位数
   * @return {string} 返回随机结果
   */
  Method.fn.randomNum = function (minNum, maxNum, decimalNum) {
    minNum = +minNum || 0;
    maxNum = +maxNum || 255;
    decimalNum = +decimalNum || 0;
    let differ = maxNum - minNum;
    let random = Math.random();
    return this.decimal(minNum + differ * random, decimalNum);
  };

  /**
   * 生成随机颜色
   * @method randomColor
   * @for Method
   * @param {boolean} type 颜色类型 true:RGB/false:二进制颜色
   * @return {string} 返回随机结果
   */
  Method.fn.randomColor = function (type) {
    type = (presence(type, 'boolean') ? type : true);
    if (type) {
      return 'rgb(' + this.randomNum() + ',' + this.randomNum() + ',' + this.randomNum() + ')';
    } else {
      return '#' + Math.random().toString(16).substring(2).substr(0, 6);
    }
  };

  /**
   * 获取鼠标/手势位置
   * @method mouse
   * @for Method/gesture
   * @return {object} 鼠标当前所在位置
   */
  Method.fn.mouse = function (e) {
    let E = e || window.event;
    let X = 0;
    let Y = 0;
    let D = {};
    if (E.pageX) {
      X = E.pageX;
      Y = E.pageY;
    } else if (E.touches && E.touches[0]) {
      X = E.touches[0].clientX;
      Y = E.touches[0].clientY;
    } else if (E.changedTouches && E.changedTouches[0]) {
      X = E.changedTouches[0].clientX;
      Y = E.changedTouches[0].clientY;
    } else {
      let sleft = 0;
      let stop = 0;
      if (document.documentElement) {
        stop = document.documentElement.scrollTop;
        sleft = document.documentElement.scrollLeft;
      } else {
        stop = document.body.scrollTop;
        sleft = document.body.scrollLeft;
      }
      X = E.clientX + sleft;
      Y = E.clientY + stop;
    }
    D.x = X;
    D.y = Y;
    return D;
  };

  /**
   * 获取鼠标/手势方向
   * @method gesture
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {function} callback 按下后的回调方法
   * @param {number} distance 间隔距离(默认10)
   */
  Method.fn.gesture = function (dom, callback, distance) {
    if (presence(dom) && presence(callback, 'function')) {
      let D = this.getDom(dom);
      let Distance = +distance || 10;
      if (!D) {
        throws(1, 'gesture', dom);
      } else {
        let that = this;
        let startX = '';
        let startY = '';
        let device = Kxui.info().device;

        let GetSlideAngle = function (dx, dy) {
          return Math.atan2(dy, dx) * 180 / Math.PI;
        };

        let GetSlideDirection = function (startX, startY, endX, endY) {
          let dy = endY - startY;
          let dx = endX - startX;
          let angle = GetSlideAngle(dx, dy);
          let result = 0;
          if (Math.abs(dx) < Distance && Math.abs(dy) < Distance) {
            return result;
          }
          if (angle >= -45 && angle < 45) {
            result = 4;
          } else if (angle >= 45 && angle < 135) {
            result = 2;
          } else if (angle >= -135 && angle < -45) {
            result = 1;
          } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
            result = 3;
          }
          return result;
        };

        /**
         * 监听鼠标/手指按下
         * @method dowm
         * @for gesture
         */
        let dowm = function () {
          startX = that.mouse().x;
          startY = that.mouse().y;
        };

        /**
         * 监听鼠标/手指抬起
         * @method up
         * @for gesture
         */
        let up = function () {
          let endX = that.mouse().x;
          let endY = that.mouse().y;
          let direction = GetSlideDirection(startX, startY, endX, endY);
          switch (direction) {
            case 0:
              callback(false);
              break;
            case 1:
              callback('T');
              break;
            case 2:
              callback('B');
              break;
            case 3:
              callback('L');
              break;
            case 4:
              callback('R');
              break;
            default:
          }
        };

        if (device === 'pc') {
          D.addEventListener('mousedown', dowm, false);
          D.addEventListener('mouseup', up, false);
        } else {
          D.addEventListener('touchstart', dowm, false);
          D.addEventListener('touchend', up, false);
        }
      }
    } else {
      throws(0, 'gesture', presence(dom) ? 'callback' : 'dom');
    }
  };

  /**
   * 防误差加法运算(浮点运算)
   * @method accAdd
   * @for Method
   * @param {number} a 计算数
   * @param {number} b 计算数
   * @return {number} 计算结果
   */
  Method.fn.accAdd = function (a, b) {
    if (presence(a, 'number') && presence(b, 'number')) {
      let r1 = '';
      let r2 = '';
      let m = '';

      try {
        r1 = a.toString().split('.')[1].length;
      } catch (e) {
        r1 = 0;
      }

      try {
        r2 = b.toString().split('.')[1].length;
      } catch (e) {
        r2 = 0;
      }

      m = Math.pow(10, Math.max(r1, r2));
      return Number((a * m + b * m) / m);
    }
    throws(0, 'accAdd', presence(a, 'number') ? 'b' : 'a');
  };

  /**
   * 防误差减法运算(浮点运算)
   * @method accSub
   * @for Method/setHis
   * @param {number} a 计算数
   * @param {number} b 计算数
   * @return {number} 计算结果
   */
  Method.fn.accSub = function (a, b) {
    if (presence(a, 'number') && presence(b, 'number')) {
      let r1 = '';
      let r2 = '';
      let m = '';
      let n = '';

      try {
        r1 = a.toString().split('.')[1].length;
      } catch (e) {
        r1 = 0;
      }

      try {
        r2 = b.toString().split('.')[1].length;
      } catch (e) {
        r2 = 0;
      }

      m = Math.pow(10, Math.max(r1, r2));
      n = (r1 >= r2) ? r1 : r2;
      return Number(this.decimal((a * m - b * m) / m, n));
    }
    throws(0, 'accSub', presence(a, 'number') ? 'b' : 'a');
  };

  /**
   * 防误差乘法运算(浮点运算)
   * @method accMul
   * @for Method
   * @param {number} a 计算数
   * @param {number} b 计算数
   * @return {number} 计算结果
   */
  Method.fn.accMul = function (a, b) {
    if (presence(a, 'number') && presence(b, 'number')) {
      let m = 0;
      let s1 = a.toString();
      let s2 = b.toString();

      try {
        m += s1.split('.')[1].length;
      } catch (e) {}

      try {
        m += s2.split('.')[1].length;
      } catch (e) {}

      return Number(Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m));
    }
    throws(0, 'accMul', presence(a, 'number') ? 'b' : 'a');
  };

  /**
   * 防误差除法运算(浮点运算)
   * @method accDiv
   * @for Method
   * @param {number} a 计算数
   * @param {number} b 计算数
   * @return {number} 计算结果
   */
  Method.fn.accDiv = function (a, b) {
    if (presence(a, 'number') && presence(b, 'number')) {
      let t1 = 0;
      let t2 = 0;
      let r1, r2;

      try {
        t1 = a.toString().split('.')[1].length;
      } catch (e) {}

      try {
        t2 = b.toString().split('.')[1].length;
      } catch (e) {}

      r1 = Number(a.toString().replace('.', ''));
      r2 = Number(b.toString().replace('.', ''));
      return Number((r1 / r2) * Math.pow(10, t2 - t1));
    }
    throws(0, 'accDiv', presence(a, 'number') ? 'b' : 'a');
  };

  /**
   * 保留任意位小数
   * @method decimal
   * @for Method/randomNum/accSub/money
   * @param {number} num 需要操作的数字
   * @param {number} len 需要保留的位数(不填为四舍五入取整)
   * @return {string} 保留后的数字
   */
  Method.fn.decimal = function (num, len) {
    if (presence(num, 'number')) {
      num = +num;
      len = +len || 0;
      return num.toFixed(len);
    }
    throws(0, 'decimal', 'num');
  };

  /**
   * 获取小数点位数
   * @method decimalPlaces
   * @for Method
   * @param {number} num 需要计算的数字
   * @return {number/boolean} 位数或状态
   */
  Method.fn.decimalPlaces = function (num) {
    if (presence(num, 'number')) {
      num = +num;
      let Y = String(num).indexOf('.') + 1;
      let count = String(num).length - Y;
      if (Y > 0) {
        return count;
      } else {
        return 0;
      }
    }
    throws(0, 'decimalPlaces', 'num');
  };

  /**
   * 金钱显示格式
   * @method money
   * @for Method
   * @param {number} num 金钱
   * @param {boolean} pau 是否每隔三位数字添加一个逗号
   * @return {string} 修改过的金钱格式
   */
  Method.fn.money = function (num, pau) {
    if (presence(num, 'number')) {
      num = +num;
      num = this.decimal(num, 2);
      pau = (presence(pau, 'boolean') ? pau : true);
      return (pau ? num.replace(/\d(?=(?:\d{3})+\b)/g, `$&,`) : num);
    }
    throws(0, 'money', 'num');
  };

  /**
   * 数字金额大写转换
   * @method moneyToChinese
   * @for Method
   * @param {number} num 金钱
   * @param {boolean} pau 是否每隔三位数字添加一个逗号
   * @return {string} 修改过的金钱格式
   */
  Method.fn.moneyToChinese = function (num) {
    if (presence(num, 'number')) {
      num = +num;
      let s = '';
      let fraction = ['角', '分'];
      let digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
      let head = num < 0 ? '欠' : '';
      let unit = [
        ['元', '万', '亿'],
        ['', '拾', '佰', '仟']
      ];
      let shiftRight = function (number, digit) {
        digit = parseInt(digit, 10);
        let value = number.toString().split('e');
        return +(value[0] + 'e' + (value[1] ? (+value[1] + digit) : digit));
      };

      let shiftLeft = function (number, digit) {
        digit = parseInt(digit, 10);
        let value = number.toString().split('e');
        return +(value[0] + 'e' + (value[1] ? (+value[1] - digit) : -digit));
      };

      num = Math.abs(num);
      for (let i = 0; i < fraction.length; i++) {
        s += (digit[Math.floor(shiftRight(num, 1 + i)) % 10] + fraction[i]).replace(/零./, '');
      }

      s = s || '整';
      num = Math.floor(num);
      for (let i$1 = 0; i$1 < unit[0].length && num > 0; i$1++) {
        let p = '';
        for (let j = 0; j < unit[1].length && num > 0; j++) {
          p = digit[num % 10] + unit[1][j] + p;
          num = Math.floor(shiftLeft(num, 1));
        }
        s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i$1] + s;
      }
      return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');
    }
    throws(0, 'moneyToChinese', 'num');
  };

  /**
   * 银行卡号(每隔四个数字添加一个空格)
   * @method bankCard
   * @for Method
   * @param {number} str 银行卡号
   * @return {string} 修改过的银行卡号格式
   */
  Method.fn.bankCard = function (str) {
    if (presence(str, 'number')) {
      str = String(str);
      let newStr = str.replace(/\d(?=(?:\d{4})+\b)/g, `$& `);
      return newStr;
    }
    throws(0, 'bankCard', 'str');
  };

  /**
   * 滚动条滚动动画
   * @method aniScroll
   * @for Method
   * @param {string/number} pageY 滚动y轴位置
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {function} callback 动画执行完毕后的回调
   */
  Method.fn.aniScroll = function (pageY, dom, callback) {
    let that = this;
    pageY = +pageY || 0;
    dom = dom ? that.getDom(dom) : false;
    clearInterval(that.getCache('(method.aniScroll)'));
    let timer = setInterval(function () {
      let currentY = (dom ? dom.scrollTop : (document.documentElement.scrollTop || document.body.scrollTop));
      let distance = ((pageY > currentY) ? (pageY - currentY) : (currentY - pageY));
      let speed = Math.ceil(distance / 10);
      let aniScrollTop = that.getCache('(method.aniScrollTop)');
      if ((parseInt(currentY) === parseInt(pageY)) || (parseInt(aniScrollTop) === parseInt(currentY))) {
        clearInterval(that.getCache('(method.aniScroll)'));
        that.delCache('(method.aniScroll)');
        that.delCache('(method.aniScrollTop)');
        if (presence(callback, 'function')) {
          callback();
        } else if (presence(callback)) {
          throws(0, 'aniScroll', 'callback');
        }
      } else {
        that.setCache('(method.aniScrollTop)', parseInt(currentY));
        if (dom) {
          dom.scrollTo(0, ((pageY > currentY) ? (currentY + speed) : (currentY - speed)));
        } else {
          window.scrollTo(0, ((pageY > currentY) ? (currentY + speed) : (currentY - speed)));
        }
      }
    }, 10);
    that.setCache('(method.aniScroll)', timer);
  };

  /**
   * 阻止事件冒泡
   * @method stopProp
   * @for Method
   */
  Method.fn.stopProp = function (event) {
    let e = event || window.event;
    if (e && e.stopPropagation) {
      e.stopPropagation();
    } else {
      e.cancelBubble = true;
    }
  };

  /**
   * 对象深拷贝
   * @method deepCopy
   * @for Method
   * @param {object} obj 需要操作的对象
   * @return {object} 拷贝返回对象
   */
  Method.fn.deepCopy = function (obj) {
    let result = (Array.isArray(obj) ? [] : presence(obj, 'object') ? {} : obj);
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (presence(obj[key], 'object')) {
          result[key] = this.deepCopy(obj[key]);
        } else {
          result[key] = obj[key];
        }
      }
    }
    return result;
  };

  /**
   * 复制文本到剪贴板
   * @method copyText
   * @for Method
   * @param {string} text 需要复制的文本内容
   * @return {boolean} 是否成功
   */
  Method.fn.copyText = function (text) {
    if (presence(text, 'string')) {
      let input = document.createElement('input');
      input.value = text;
      this.getDom('body').appendChild(input);
      input.select();
      input.setSelectionRange(0, input.value.length);
      document.execCommand('Copy');
      this.getDom('body').removeChild(input);
      return true;
    }
    throws(0, 'copyText', 'text');
  };

  /**
   * 设置元素样式(行内样式)
   * @method setStyle
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {object} sty 需要设置的样式对象
   * @return {boolean} 是否成功
   */
  Method.fn.setStyle = function (dom, sty) {
    if (presence(dom) && presence(sty, 'object')) {
      dom = this.getDom(dom);
      if (!dom.length) {
        for (let s in sty) {
          dom.style[s] = sty[s];
        }
      } else {
        for (let i = 0; i < dom.length; i++) {
          for (let s in sty) {
            dom[i].style[s] = sty[s];
          }
        }
      }
      return true;
    }
    throws(0, 'setStyle', presence(dom) ? 'sty' : 'dom');
  };

  /**
   * 获取元素样式
   * @method getStyle
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string} arr 需要获取的样式名称
   * @param {boolean} unit 是否保留px单位(默认保留:true)
   * @return {string/boolean} 是否查询成功布尔值或样式值
   */
  Method.fn.getStyle = function (dom, arr, unit) {
    if (presence(dom) && presence(arr, 'string')) {
      let D = this.getDom(dom);
      if (!D) {
        throws(1, 'getStyle', dom);
      } else {
        unit = (presence(unit, 'boolean') ? unit : true);
        let S = '';
        if (D.currentStyle) {
          S = D.currentStyle[arr];
        } else if (window.getComputedStyle) {
          S = document.defaultView.getComputedStyle(D, null)[arr];
        }
        if (presence(S) && S.indexOf('px') >= 0 && !unit) {
          S = Number(this.queStr(S, 'px', false));
        }
        return (presence(S) ? S : false);
      }
      return false;
    }
    throws(0, 'getStyle', presence(dom) ? 'arr' : 'dom');
  };

  /**
   * 字符串/对象去空格
   * @method delSpace
   * @for Method
   * @param {string/object} ope 需要操作的字符串/对象
   * @return {string/object} 返回去掉空格的字符串/对象
   */
  Method.fn.delSpace = function (ope) {
    if (presence(ope, 'string') || presence(ope, 'object')) {
      if (presence(ope, 'string')) {
        return ope.replace(/[ ]/g, '');
      } else {
        for (let prop in ope) {
          if (presence(ope[prop], 'object') && Array.isArray(ope[prop])) {
            let list = ope[prop];
            for (let i = 0; i < list.length; i++) {
              list[i] = this.delSpace(list[i]);
            }
          } else if (presence(ope[prop], 'object') && (ope[prop]) instanceof Object) {
            ope[prop] = this.delSpace(ope[prop]);
          } else if (presence(ope[prop], 'string')) {
            if (prop !== 'FormMeta') {
              ope[prop] = ope[prop].replace(/[ ]/g, '');
            }
          }
        }
        return ope;
      }
    }
    throws(0, 'delSpace', 'ope');
  };

  /**
   * 替换所有HTML标签
   * @method repHtmlTag
   * @for Method
   * @param {string} str 完整的HTML标签
   * @return {string} 返回字符串HTML标签
   */
  Method.fn.repHtmlTag = function (str) {
    if (presence(str, 'string')) {
      while (str.indexOf('>') >= 0 || str.indexOf('<') >= 0) {
        str = str.replace('<', '&lt;').replace('>', '&gt;');
      }
      return str;
    }
    throws(0, 'repHtmlTag', 'str');
  };

  /**
   * 去掉所有HTML标签
   * @method delHtmlTag
   * @for Method
   * @param {string} str 完整的HTML标签
   * @return {string} 返回去掉所有HTML标签的字符串
   */
  Method.fn.delHtmlTag = function (str) {
    if (presence(str, 'string')) {
      return str.replace(/<[^>]+>/g, '');
    }
    throws(0, 'delHtmlTag', 'str');
  };

  /**
   * 键盘回车事件
   * @method enter
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {function} callback 按下后的回调方法
   */
  Method.fn.enter = function (dom, callback) {
    if (presence(dom) && presence(callback, 'function')) {
      let D = this.getDom(dom);
      if (!D) {
        throws(1, 'enter', dom);
      } else {
        D.onkeydown = function (event) {
          let e = event || window.event;
          if (e && e.keyCode === 13) {
            if (presence(callback, 'function')) {
              callback();
            } else {
              throws(0, 'enter', 'callback');
            }
          }
        };
      }
    } else {
      throws(0, 'enter', presence(dom) ? 'callback' : 'dom');
    }
  };

  /**
   * 移动端尺寸自适应
   * @method fontAdapt
   * @for Method
   * @param {number} root 自适应根节点(默认30)
   * @param {number} screen 自适应屏幕宽度(默认750)
   */
  Method.fn.fontAdapt = function (root, screen) {
    root = +root || 30;
    screen = +screen || 750;
    let docEl = document.documentElement;
    let resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
    let recalc = function () {
      let clientWidth = docEl.clientWidth;
      if (clientWidth) {
        window.font = docEl.style.fontSize = parseInt(root * (clientWidth / screen)) + 'px';
      }
    };
    if (document.addEventListener) {
      window.addEventListener(resizeEvt, recalc, false);
      document.addEventListener('DOMContentLoaded', recalc, false);
    }
    recalc();
  };

  /**
   * 获取百分比
   * @method percent
   * @for Method
   * @param {number} num 当前数
   * @param {number} total 总数(默认100)
   * @param {boolean} symbol 是否携带百分比单位(默认携带:true)
   * @return {string} 计算后的百分比
   */
  Method.fn.percent = function (num, total, symbol) {
    if (presence(num, 'number')) {
      num = +num;
      total = +total || 100;
      symbol = (presence(symbol, 'boolean') ? symbol : true);
      return total <= 0 ? '0%' : (Math.round(num / total * 10000) / 100.00) + (symbol ? '%' : '');
    }
    throws(0, 'percent', 'num');
  };

  /**
   * 监听输入框事件(处理中文输入问题)
   * @method monitor
   * @for Method
   * @param {string/object} dom 节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {function} callback 按下后的回调方法
   */
  Method.fn.monitor = function (dom, callback) {
    if (presence(dom) && presence(callback, 'function')) {
      let D = this.getDom(dom);
      if (!D) {
        throws(1, 'monitor', dom);
      } else {
        let doing = true;
        D.addEventListener('compositionstart', function () {
          doing = false;
        }, false);

        D.addEventListener('compositionend', function () {
          doing = true;
          callback(D.value);
        }, false);

        D.addEventListener('input', function () {
          if (doing) {
            callback(D.value);
          }
        }, false);
      }
    } else {
      throws(0, 'monitor', presence(dom) ? 'callback' : 'dom');
    }
  };

  /**
   * 主动防御
   * 对于我们操作的数据，尤其是由 API 接口返回的，时常会有一个很复杂的深层嵌套的数据结构
   * 为了代码的健壮性，很多时候需要对每一层访问都作空值判断，代码看起来相当不美观，因此提供了一个非常简洁明了的原生的方式
   * @method getIn
   * @for Method
   * @param {object} obj 操作对象
   * @param {Array} list 属性列表
   * @return {*} 如果正常访问到，则返回对应的值，否则返回 null。
   */
  Method.fn.getIn = function (obj, list) {
    if (presence(obj, 'object') && presence(list, 'object')) {
      return list.reduce(function (xs, x) {
        return (xs && xs[x]) ? xs[x] : null;
      }, obj);
    }
    throws(0, 'getIn', presence(obj, 'object') ? 'list' : 'obj');
  };

  /**
   * 测试函数所花费的时间
   * @method timeTaken
   * @for Method
   * @param {function} callback 需要测试的函数
   * @return {string} 在控制台返回(F12)
   *
   * timeTaken(() => Math.pow(2, 10));
   */
  Method.fn.timeTaken = function (callback) {
    if (presence(callback, 'function')) {
      console.time('timeTaken');
      let time = callback();
      console.timeEnd('timeTaken');
      return time;
    }
    throws(0, 'timeTaken', 'callback');
  };

  /**
   * 元素拖拽
   * @method drag
   * @for Method
   * @param {string/object} dom 事件发生节点，节点名称/class值/id值/属性名称/原生dom对象/jquery对象
   * @param {string/object} box 拖拽移动节点，节点名称/class值/id值/属性名称/原生dom对象/jquery对象(不填将拖动dom)
   */
  Method.fn.drag = function (dom, box) {
    if (presence(dom)) {
      let that = this;
      let D = that.getDom(dom);
      let B = box ? that.getDom(box) : D;
      let I = Kxui.info();
      let doc = I.document.c;
      let dowmX = 0;
      let dowmY = 0;
      let moveX = 0;
      let moveY = 0;
      let saveX = B.offsetLeft;
      let saveY = B.offsetTop;
      let position = that.getStyle(B, 'position');

      let move = function (e) {
        moveX = that.mouse(e).x - dowmX + saveX;
        moveY = that.mouse(e).y - dowmY + saveY;
        if (moveX <= 0) {
          moveX = 0;
        }
        if (moveY <= 0) {
          moveY = 0;
        }
        if (moveX >= I.size.cDocW - B.offsetWidth) {
          moveX = I.size.cDocW - B.offsetWidth;
        }
        if (moveY >= I.size.cDocH - B.offsetHeight) {
          moveY = I.size.cDocH - B.offsetHeight;
        }

        B.style.left = moveX + 'px';
        B.style.top = moveY + 'px';
      };

      let up = function () {
        saveX = B.offsetLeft;
        saveY = B.offsetTop;
        doc.removeEventListener('mousemove', move, false);
        doc.removeEventListener('mouseup', up, false);
      };

      let dowm = function (e) {
        dowmX = that.mouse(e).x;
        dowmY = that.mouse(e).y;
        doc.addEventListener('mousemove', move, false);
        doc.addEventListener('mouseup', up, false);
      };

      if (!position || position === 'static') {
        that.setStyle(B, {
          'position': 'relative'
        });
      }

      D.addEventListener('mousedown', dowm, false);
    } else {
      throws(0, 'drag', 'dom');
    }
  };

  /**
   * 判断数据是否为空及确认数据类型是否正确
   * @method presence
   * @for Method
   * @param {object} object 需要参与判断的对象
   * @param {string} dataType 需要判断的数据类型
   */
  function presence(object, dataType) {
    if (typeof object === 'undefined' || object === null || object === '') {
      return false;
    } else if (dataType) {
      if (dataType === 'number') {
        object = +object;
        return !isNaN(object);
      } else {
        return typeof object === dataType;
      }
    } else {
      return true;
    }
  }

  /**
   * 控制台错误/警告
   * @method throws
   * @for Method
   * @param {number} num 输入警告文案编号
   * @param {string} name 发生错误的方法
   * @param {string} field 错误其他说明
   */
  function throws(num, name, field) {
    if (Kxui.configuration.debug) {
      let nums = {};
      nums[0] = '配置参数 {' + field + '} 为空或存在数据类型错误';
      nums[1] = '无法找到 {' + field + '} 节点或存在多个 {' + field + '} 节点';
      console.warn('Kxui-' + Kxui.about.version + '： 模块 {method[' + name + ']} ' + nums[num] + '，请检查修改。');
    }
  }

  return new Method();

}));